useFormTable
封装了常用的 AntD Form 与 AntD Table 联动逻辑,并且同时支持 AntD V3与V4.
以下示例均为 AntD V4 版本。
一、Form 与 Table 联动
/**
* title: Form与Table联动
* description: useFormTable 接收 form 实例后,会返回 search 对象。
*/
import React from 'react';
import { Form, Row, Col, Input, Button, Select, Table } from 'antd';
import { useFormTable } from '@umijs/hooks';
import { PaginatedParams } from '@umijs/hooks/lib/useFormTable';
interface Item {
name: {
last: string;
};
email: string;
phone: string;
gender: 'male' | 'female';
}
interface Result {
total: number;
list: Item[];
}
const getTableData = (
{ current, pageSize }: PaginatedParams[0],
formData: Object,
): Promise<Result> => {
let query = `page=${current}&size=${pageSize}`;
Object.entries(formData).forEach(([key, value]) => {
if (value) {
query += `&${key}=${value}`;
}
});
return fetch(`https://randomuser.me/api?results=55&${query}`)
.then((res) => res.json())
.then((res) => ({
total: res.info.results,
list: res.results,
}));
};
export default () => {
const [form] = Form.useForm();
const { tableProps, search } = useFormTable(getTableData, {
defaultPageSize: 5,
form,
});
const { type, changeType, submit, reset } = search;
const columns = [
{
title: 'name',
dataIndex: 'name.last',
},
{
title: 'email',
dataIndex: 'email',
},
{
title: 'phone',
dataIndex: 'phone',
},
{
title: 'gender',
dataIndex: 'gender',
},
];
const advanceSearchForm = (
<div>
<Form form={form}>
<Row gutter={24}>
<Col span={8}>
<Form.Item label="name" name="name">
<Input />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="email" name="email">
<Input />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="phone" name="phone">
<Input />
</Form.Item>
</Col>
</Row>
<Row>
<Form.Item style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button type="primary" onClick={submit}>
Search
</Button>
<Button type="default" onClick={reset}>
reset
</Button>
<Button type="link" onClick={changeType}>
simple search
</Button>
</Form.Item>
</Row>
</Form>
</div>
);
const searchForm = (
<div style={{ marginBottom: 16 }}>
<Form form={form} style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Form.Item name="gender">
<Select onChange={submit} style={{ width: 120, marginRight: 16 }}>
<Select.Option value="">all</Select.Option>
<Select.Option value="male">male</Select.Option>
<Select.Option value="female">female</Select.Option>
</Select>
</Form.Item>
<Form.Item label="名称" name="name">
<Input.Search style={{ width: 240 }} onSearch={submit} />
</Form.Item>
<Button type="link" onClick={changeType}>
Advanced Search
</Button>
</Form>
</div>
);
return (
<div>
{type === 'simple' ? searchForm : advanceSearchForm}
<Table columns={columns} bordered rowKey="email" {...tableProps} />
</div>
);
};
二、数据缓存
/**
* title: 数据缓存
* desc: 通过 cacheKey 可以实现 Form 和 Table 数据缓存。
*/
import React, { useState } from 'react';
import { Table, Input, Form, Button } from 'antd';
import { useFormTable } from '@umijs/hooks';
import { PaginatedParams } from '@umijs/hooks/lib/useFormTable';
interface Item {
name: {
last: string;
};
email: string;
phone: string;
gender: 'male' | 'female';
}
interface Result {
total: number;
list: Item[];
}
const getTableData = (
{ current, pageSize }: PaginatedParams[0],
formData: Object,
): Promise<Result> => {
let query = `page=${current}&size=${pageSize}`;
Object.entries(formData).forEach(([key, value]) => {
if (value) {
query += `&${key}=${value}`;
}
});
return fetch(`https://randomuser.me/api?results=55&${query}`)
.then((res) => res.json())
.then((res) => ({
total: res.info.results,
list: res.results,
}));
};
const AppList = () => {
const [form] = Form.useForm();
const { tableProps, params, search } = useFormTable(getTableData, {
defaultPageSize: 5,
form,
cacheKey: 'tableProps',
});
const { sorter = {}, filters = {} } = params[0] || ({} as any);
const { type, changeType, submit, reset } = search || {};
const columns = [
{
title: 'name',
dataIndex: 'name.last',
},
{
title: 'email',
dataIndex: 'email',
},
{
title: 'phone',
dataIndex: 'phone',
sorter: true,
sortOrder: sorter.field === 'phone' && sorter.order,
},
{
title: 'gender',
dataIndex: 'gender',
filters: [
{ text: 'male', value: 'male' },
{ text: 'female', value: 'female' },
],
filteredValue: filters.gender,
},
];
const searchForm = (
<div style={{ marginBottom: 16 }}>
<Form form={form} style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Form.Item name="name">
<Input placeholder="enter name" style={{ width: 140, marginRight: 16 }} />
</Form.Item>
{type === 'advance' && (
<>
<Form.Item name="email">
<Input placeholder="enter email" style={{ width: 140, marginRight: 16 }} />
</Form.Item>
<Form.Item name="phone">
<Input placeholder="enter phone" style={{ width: 140, marginRight: 16 }} />
</Form.Item>
</>
)}
<Button type="primary" onClick={submit}>
Search
</Button>
<Button onClick={reset} style={{ marginLeft: 8 }}>
Reset
</Button>
<Button type="link" onClick={changeType}>
{type === 'simple' ? 'Expand' : 'Close'}
</Button>
</Form>
</div>
);
return (
<div>
{searchForm}
<Table columns={columns} rowKey="email" {...tableProps} />
</div>
);
};
export default () => {
const [show, setShow] = useState(true);
return (
<div>
<Button onClick={() => setShow(!show)}>toggle</Button>
{show && <AppList />}
</div>
);
};
/**
* title: 使用 defaultParams
* desc: useFormTable 通过 defaultParams 设置初始化值,defaultParams 是一个数组,第一个值为分页相关参数,第二个值为表单相关数据。如果有第二个值,我们会帮您初始化表单!需要注意的是,初始化的表单数据可以填写 simple 与 advance 全量的表单数据,我们会帮您挑选当前激活的类型中的表单数据。
*/
import React from 'react';
import { Button, Col, Form, Input, Row, Table, Select } from 'antd';
import { WrappedFormUtils } from 'antd/lib/form/Form';
import { useFormTable } from '@umijs/hooks'
import { PaginatedParams } from '@umijs/hooks/useFormTable/lib'
const { Option } = Select;
interface Item {
name: {
last: string;
};
email: string;
phone: string;
gender: 'male' | 'female';
}
interface Result {
total: number;
list: Item[];
}
interface AppListProps {
form: WrappedFormUtils;
}
const getTableData = ({ current, pageSize }: PaginatedParams[0], formData: Object): Promise<Result> => {
let query = `page=${current}&size=${pageSize}`;
Object.entries(formData).forEach(([key, value]) => {
if (value) {
query += `&${key}=${value}`
}
});
return fetch(`https://randomuser.me/api?results=55&${query}`)
.then(res => res.json())
.then(res => ({
total: res.info.results,
list: res.results,
}));
};
const AppList = (props: AppListProps) => {
const { getFieldDecorator } = props.form;
const { tableProps, search } = useFormTable(getTableData, {
form: props.form,
defaultParams: [
{ current: 2, pageSize: 5 },
{ name: 'hello', email: 'abc@gmail.com', gender: 'female' }
],
defaultType: 'advance'
});
const { type, changeType, submit, reset } = search;
const columns = [
{
title: 'name',
dataIndex: 'name.last',
},
{
title: 'email',
dataIndex: 'email',
},
{
title: 'phone',
dataIndex: 'phone',
},
{
title: 'gender',
dataIndex: 'gender',
},
];
const advanceSearchForm = (
<div>
<Form>
<Row gutter={24}>
<Col span={8}>
<Form.Item label="name">
{getFieldDecorator('name')(<Input placeholder="name" />)}
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="email">
{getFieldDecorator('email')(<Input placeholder="email" />)}
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="phone">
{getFieldDecorator('phone')(<Input placeholder="phone" />)}
</Form.Item>
</Col>
</Row>
<Row>
<Form.Item style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button type="primary" onClick={submit}>
Search
</Button>
<Button onClick={reset} style={{ marginLeft: 16 }}>
Reset
</Button>
<Button type="link" onClick={changeType}>
Simple Search
</Button>
</Form.Item>
</Row>
</Form>
</div>
);
const searchFrom = (
<div style={{ marginBottom: 16 }}>
<Form style={{ display: 'flex', justifyContent: 'flex-end' }}>
{getFieldDecorator('gender', {
initialValue: 'male',
})(
<Select style={{ width: 120, marginRight: 16 }} onChange={submit}>
<Option value="">all</Option>
<Option value="male">male</Option>
<Option value="female">female</Option>
</Select>,
)}
{getFieldDecorator('name')(
<Input.Search placeholder="enter name" style={{ width: 240 }} onSearch={submit} />,
)}
<Button type="link" onClick={changeType}>
Advanced Search
</Button>
</Form>
</div>
);
return (
<div>
{type === 'simple' ? searchFrom : advanceSearchForm}
<Table columns={columns} rowKey="email" {...tableProps} />
</div>
);
};
export default Form.create()(AppList);
三、API
useFormTable 基于 useRequest 实现,所有的 useRequest Pagination API 均可以直接使用。比如 cacheKey、manual 等。
useFormTable 额外增加了 result.search 和 options.form。
const {
...,
search: {
type: 'simple' | 'advance';
changeType: () => void;
submit: () => void;
reset: () => void;
};
} = useFormTable(
service,
{
...,
form,
defaultType: 'simple' | 'advance',
defualtParams: [pagination, formData]
}
)